#include "spi.h"

// 初始化
void SPI_Init(void)
{
    // 1. 开启时钟
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
    RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
    RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;

    // 2. GPIO工作模式
    // PC13：通用推挽输出，CNF = 00，MODE = 11
    GPIOC->CRH |= GPIO_CRH_MODE13;
    GPIOC->CRH &= ~GPIO_CRH_CNF13;

    // PA5、PA7: 复用推挽输出，CNF = 10，MODE = 11
    GPIOA->CRL |= GPIO_CRL_MODE5;
    GPIOA->CRL |= GPIO_CRL_CNF5_1;
    GPIOA->CRL &= ~GPIO_CRL_CNF5_0;

    GPIOA->CRL |= GPIO_CRL_MODE7;
    GPIOA->CRL |= GPIO_CRL_CNF7_1;
    GPIOA->CRL &= ~GPIO_CRL_CNF7_0;

    // PA6：MISO，浮空输入，CNF = 01，MODE = 00
    GPIOA->CRL &= ~GPIO_CRL_MODE6;
    GPIOA->CRL &= ~GPIO_CRL_CNF6_1;
    GPIOA->CRL |= GPIO_CRL_CNF6_0;

    // 3. SPI相关配置
    // 3.1 配置SPI为主模式
    SPI1->CR1 |= SPI_CR1_MSTR;

    // 3.2 使用软件控制片选信号，直接拉高
    SPI1->CR1 |= SPI_CR1_SSM;
    SPI1->CR1 |= SPI_CR1_SSI;

    // 3.3 配置工作模式0，时钟极性和相位
    SPI1->CR1 &= ~SPI_CR1_CPOL;
    SPI1->CR1 &= ~SPI_CR1_CPHA;

    // 3.4 配置时钟分频系数，波特率选择：BR-001
    SPI1->CR1 &= ~SPI_CR1_BR;
    SPI1->CR1 |= SPI_CR1_BR_0;

    // 3.5 设置数据帧格式
    SPI1->CR1 &= ~SPI_CR1_DFF;

    // 3.6 配置高位先行MSB
    SPI1->CR1 &= ~SPI_CR1_LSBFIRST;

    // 3.7 SPI模块使能
    SPI1->CR1 |= SPI_CR1_SPE;
}

// 数据传输的开始和结束
void SPI_Start(void)
{
    CS_LOW;
}
void SPI_Stop(void)
{
    CS_HIGH;
}

// 主从设备交换一个字节的数据
uint8_t SPI_SwapByte(uint8_t byte)
{
    // 1. 将要发送的数据byte写入发送缓冲区
    // 1.1 等待发送缓冲区为空
    while ((SPI1->SR & SPI_SR_TXE) == 0)
    {}
    
    // 1.2 将数据byte写入DR寄存器
    SPI1->DR = byte;

    // 2. 读取MISO发来的数据
    // 2.1 等待接收缓冲区为非空
    while ((SPI1->SR & SPI_SR_RXNE) == 0)
    {}
    // 2.1 从接收缓冲区读取数据，返回
    return (uint8_t)(SPI1->DR & 0xff);
}

